#include "fxcc/mono/CSharpImporter.h"
#include "e2d/ui/Utils.h"

CSharpMetaCacheFile CSharpImpoter::m_CSharpCacheFile;
std::string CSharpImpoter::m_CSharpMetaPath = ".metamap/csharp.metamap";
std::vector<std::string> CSharpImpoter::m_DependencyDir;

bool CSharpImpoter::ImportFile(const fxcc::File& _f1)
{
	switch (_f1.m_FileType)
	{
	case fxcc::FileType::_CS_:
		return ImportCSharpFile(_f1);
	default:
		return false;
	}
}

bool CSharpImpoter::Availed(const fxcc::File& file)
{
    return file.IsCSharp();
}

bool CSharpImpoter::ImportCSharpFile(const fxcc::File& file)
{
	auto& cacheFile = m_CSharpCacheFile.m_Caches[file.m_RelativePath];
	
	fs::path targetDir = fs::path(m_LibraryPath) / m_DllPath;

	MetaMapIndex metaMapIndex;
	metaMapIndex.SetDll(targetDir.string(), file.m_RelativePath, 0);
	metaMapIndex.SetName(fxcc::Base::GetNoSuffixName(file.m_FileName));
	CompileCSToDll(metaMapIndex.m_NativeFile, metaMapIndex.m_TargetFilePath);
	
	cacheFile.m_DllMetas.push_back(metaMapIndex);

	return true;
}

bool CSharpImpoter::CompileCSToDll(const std::string& csFile, const std::string& target)
{
	fxcc::Base::CreateParentDirs(target);

	kainjow::mustache::mustache m1 = 
		R"(mcs -target:library -out:{{{target}}}  {{#deps}} {{{.}}}/*.cs {{/deps}}  {{{source}}})";
	
	kainjow::mustache::data d1;
	d1.set("source", csFile);
	d1.set("target", target);
	kainjow::mustache::list l1;
	for (const auto& dep : m_DependencyDir)
	{
		l1.push_back(dep);
	}
	d1.set("deps", l1);
	std::string cmdText = m1.render(d1);

	ztclog::info("[%s] %s", m_Name.c_str(), cmdText.c_str());
	return sysx::System::ExecuteCmd(cmdText);
}

bool CSharpImpoter::SaveCache()
{
	fxcc::yml::Serializer serializer;
	FXCC_FAILED(serializer.EncodePath<CSharpMetaCacheFile>(m_CSharpMetaPath, m_CSharpCacheFile));
	return true;
}

bool CSharpImpoter::LoadCache()
{
	fxcc::yml::Serializer serializer;
	FXCC_FAILED(serializer.DecodePath<CSharpMetaCacheFile>(m_CSharpMetaPath, m_CSharpCacheFile));
	return true;
}

bool CSharpImpoter::AddDepPath(const std::string& dir)
{
	bool flag = fs::exists(dir) && fs::is_directory(dir);
	if(flag)
		m_DependencyDir.push_back(dir);
	return flag;
}
